package org.summerframework.component.security.context;


import org.summerframework.component.security.LoginData;
import org.summerframework.core.base.result.ResultDTO;
import org.summerframework.core.exception.AppException;
import lombok.Getter;
import lombok.Setter;
import org.apache.commons.lang3.StringUtils;

import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;


/**
 * This class acts as runtime context, API client can use it to get request
 * parameters, spring bean, and <code>PageData</code>, its instance will be
 * stored <code>ThreadLocal</code>.
 * <p>
 * <pre>
 * 		<B>to get request parameter<B>
 * 		requestCxt.getParameters().getXXX("key"); XXX denotes String, Boolean, Long, etc.
 *      <B>to set request parameter<B>
 *      requestCxt.getParameters().setObject("key", value)
 *      <B>to set cookie<B>
 *      requestCxt.getCookies().setCookie(name, value, timeToLive)
 *      <B>to get spring bean<B>
 *      requestCxt.getSpringBean("beanName")
 * </pre>
 */
@Getter
@Setter
public class RequestContext<T> {
    private HttpServletRequest request;
    private HttpServletResponse response;
    private ServletContext servletContext;
    private HttpSession session;
    private final static ThreadLocal<RequestContext> requestContext = new RequestContextThreadLocal();
    private String redirectTarget;
    private LoginData<T> loginData;
    private long timein;
    private long timeout;
    private AppException exception;
    private String requestIp;
    private Boolean isAny = false;
    private String permissions;

    public static void clean() {
        requestContext.remove();
    }

    public Boolean isPermissions(String permissions) {
        return StringUtils.equals(this.permissions, permissions);
    }

    RequestContext() {
        this.timein = System.currentTimeMillis();
        requestContext.set(this);
    }

    private static class RequestContextThreadLocal extends ThreadLocal<RequestContext> {
        @Override
        protected RequestContext initialValue() {
            return new RequestContext();
        }
    }

    public ResultDTO getReusltLoginDate() {
        if (exception != null) {
            return exception.getResultDTO();
        }

        return ResultDTO.ok(loginData);
    }

    public static <T> RequestContext<T> getContext() {
        return (RequestContext<T>) requestContext.get();
    }

    public LoginData<T> getLoginData(Class<LoginData> dClass) {
        if (loginData != null) {
            return loginData;
        } else {
            return setLoginData(null, dClass);
        }
    }

    public void setLoginData(LoginData<T> loginData) {
        this.loginData = loginData;
    }

    public LoginData setLoginData(LoginData<T> loginData, Class<LoginData> dClass) {
        if (loginData != null) {
            this.loginData = loginData;
        } else {
            try {
                this.loginData = dClass.newInstance();
            } catch (InstantiationException | IllegalAccessException e) {
                e.printStackTrace();
            }
        }

        return this.loginData;
    }
}
